package com.googlecode.yoohoo.xmppcore.protocol.parsing;

import java.util.List;

import com.googlecode.yoohoo.xmppcore.protocol.XmlLangText;
import com.googlecode.yoohoo.xmppcore.protocol.XmppProtocolException;
import com.googlecode.yoohoo.xmppcore.protocol.stanza.Presence;
import com.googlecode.yoohoo.xmppcore.protocol.stanza.error.BadRequest;

public class PresenceParserFactory extends AbstractXmppParserFactory<Presence> {
	private static final ProtocolKey PROTOCOL_KEY_PRESENCE = new ProtocolKey("presence", null);

	@Override
	public IXmppParser<Presence> createParser() {
		return new PresenceParser();
	}
	
	private class PresenceParser extends StanzaParser<Presence> {
		private static final String PATH_PRESENCE_STATUS = "presence/status";
		private static final String PATH_PRESENCE_SHOW = "presence/show";
		private static final String PATH_PRESENCE_PRIORITY = "presence/priority";
		private static final String PATH_PRESENCE = "presence";
		
		private XmlLangText status;

		@Override
		protected Presence createStanza() {
			return new Presence();
		}
		
		@Override
		protected void doProcessAttributes(String path, List<Attribute> attributes) {
			if (PATH_PRESENCE_STATUS.equals(path)) {
				status = new XmlLangText();
				status.setXmlLang(ParsingUtils.readXmlLang(attributes));
			} else if (!PATH_PRESENCE_SHOW.equals(path) && !PATH_PRESENCE_PRIORITY.equals(path)) {
				throw new XmppProtocolException(new BadRequest(String.format("Invalid element '%s'.", path)));
			} else if (attributes.size() != 0) {
				throw new XmppProtocolException(new BadRequest("Not allow attribute here."));
			}
		}
		
		@Override
		public void processText(String path, String text) {
			if (PATH_PRESENCE_SHOW.equals(path)) {
				if (stanza.getShow() != null) {
					throw new XmppProtocolException(new BadRequest("Reduplicated 'show' element"));
				}
				
				try {
					stanza.setShow(text);
				} catch (IllegalArgumentException e) {
					throw new XmppProtocolException(new BadRequest(String.format(
							"Invalid presence show type '%s'.", text)));
				}
			} else if (PATH_PRESENCE_STATUS.equals(path)) {
				status.setText(text);
				stanza.getStatus().add(status);
				status = null;
			} else if (PATH_PRESENCE_PRIORITY.equals(path)) {
				if (stanza.getPriority() != null) {
					throw new XmppProtocolException(new BadRequest("Reduplicated 'priority' element ."));
				}
				
				try {
					stanza.setPriority(Integer.parseInt(text));
				} catch (NumberFormatException e) {
					throw new XmppProtocolException(new BadRequest("Value of attribute 'priority' must be an integer."));
				}
				
				// (rfc3921 2.2.2.3)
				if (stanza.getPriority() < -128 || stanza.getPriority() > 127) {
					throw new XmppProtocolException(new BadRequest("Value of attribute 'priority' must be between -128 and 127."));
				}
			} else if (PATH_PRESENCE.equals(path)) {
				if (text != null && !"".equals(text)) {
					throw new XmppProtocolException(new BadRequest("Text isn't allowed in presence element."));
				}
			} else {
				throw new XmppProtocolException(new BadRequest(String.format("Invalid parsing path '%s'", path)));
			}
		}	
	}

	@Override
	public ProtocolKey getProtocolKey() {
		return PROTOCOL_KEY_PRESENCE;
	}
	
}
